{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Quantum teleportation and superdense coding"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Quantum teleportation\n",
    "\n",
    "We are going to use Qiskit to implement the quantum teleportation protocol"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%matplotlib inline\n",
    "\n",
    "from qiskit import *\n",
    "from qiskit.visualization import *\n",
    "from qiskit.tools.monitor import *\n",
    "import random, time\n",
    "\n",
    "# We will create a random qubit by directly assigning random amplitudes\n",
    "\n",
    "a1 = random.random()*2 -1 #Uniform number in [-1,1]\n",
    "a2 = random.random()*2 -1\n",
    "b1 = random.random()*2 -1\n",
    "b2 = random.random()*2 -1\n",
    "\n",
    "# We need to normalize\n",
    "\n",
    "norm = (a1**2 + a2**2 + b1**2 + b2**2)**0.5\n",
    "\n",
    "c1 = complex(a1/norm,a2/norm) #Amplitude for |0> \n",
    "c2 = complex(b1/norm,b2/norm) #Amplitude for |1>\n",
    "\n",
    "psi = QuantumRegister(1, name  = 'psi')  # The qubit to teleport\n",
    "bell = QuantumRegister(2, name = 'bell') # The shared entangled pair \n",
    "c = ClassicalRegister(2, name  = 'c') # Two classical bits for the measures\n",
    "\n",
    "teleport = QuantumCircuit(psi,bell,c) # We create the circuit with the two quantum registers and the classical bits\n",
    "teleport.initialize([c1,c2],psi) # We set the amplitudes for Alice's quibt\n",
    "teleport.barrier()\n",
    "\n",
    "print(\"Alice's qubit is:\")\n",
    "print(c1,\"|0> + \",\n",
    "      c2,\"|1>\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Now we create the Bell pair\n",
    "\n",
    "teleport.h(bell[0])\n",
    "teleport.cx(bell[0],bell[1])\n",
    "teleport.barrier()\n",
    "\n",
    "# We apply CNOT to |psi> and Alice's part of the entangled pair\n",
    "# We also apply the H gate\n",
    "# Then, Alice measure her qubits and send the results to Bob\n",
    "\n",
    "teleport.cx(psi,bell[0])\n",
    "teleport.h(psi)\n",
    "teleport.measure([psi[0],bell[0]],c)\n",
    "teleport.barrier()\n",
    "\n",
    "# Bob applies his gates depending on the values received from Alice \n",
    "\n",
    "teleport.cx(bell[0],bell[1])\n",
    "teleport.cz(psi,bell[1])\n",
    "\n",
    "teleport.draw(output='mpl')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# We run the circuit and access the amplitudes to check that Bob got the qubit\n",
    "\n",
    "backend = Aer.get_backend('statevector_simulator')\n",
    "job = execute(teleport, backend)\n",
    "outputstate = job.result().get_statevector()\n",
    "print(outputstate)\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Supendense coding\n",
    "\n",
    "Now, we are going to implement a circuit to simulate superdense coding"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# We start by creating the Bell pair that Alice and Bob share\n",
    "\n",
    "bell = QuantumRegister(2, name = 'bell') # We need two qubits\n",
    "c = ClassicalRegister(2) # And two bits for the measurements \n",
    "dense = QuantumCircuit(bell,c)\n",
    "dense.h(bell[0])\n",
    "dense.cx(bell[0],bell[1])\n",
    "dense.barrier()\n",
    "\n",
    "# We randomly choose which bits to send\n",
    "\n",
    "b1 = random.randint(0,1)\n",
    "b2 = random.randint(0,1)\n",
    "\n",
    "print(\"Alice wants to send \",b1,b2)\n",
    "\n",
    "# And we apply the gates accordingly\n",
    "\n",
    "if(b2==1):\n",
    "    dense.x(bell[0])\n",
    "if(b1==1):\n",
    "    dense.z(bell[0])\n",
    "    \n",
    "dense.barrier()\n",
    "\n",
    "dense.draw(output='mpl')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Alice sends her qubit to Bob, who applies his gates and measures\n",
    "\n",
    "dense.cx(bell[0],bell[1])\n",
    "dense.h(bell[0])\n",
    "dense.barrier()\n",
    "dense.measure(bell,c)\n",
    "dense.draw(output='mpl')\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Let us run the circuit\n",
    "\n",
    "backend = Aer.get_backend('qasm_simulator')\n",
    "job = execute(dense, backend, shots = 1, memory = True)\n",
    "result = job.result().get_memory()\n",
    "\n",
    "print(\"Bob has received \",int(result[0][1]),int(result[0][0]))\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
